﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using weBoardSvr.Properties;
using MessageBox = System.Windows.MessageBox;

namespace weBoardSvr
{
    /// <summary>
    /// Interaction logic for mainWnd.xaml
    /// </summary>
    public partial class mainWnd
    {
        #region Private variables
        private readonly NotifyIcon _ni;                    //our tray icon
        private bool _canClose;                             //we need to close connections or don't
        private readonly weBoardServer _svr;                //server object that does all
        #endregion Private variables

        #region Public members
        /// <summary>
        /// Main
        /// </summary>
        public mainWnd()
        {
            InitializeComponent();
            _svr = new weBoardServer();
            weBoardServer.SetGuiElements(LblClientsCount);
            LblShowHost.Content = Environment.MachineName;
            LblShowIntIp.Content = GetLocalIp();
            _svr.CheckInternet(OnPing);
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(ResolveExternalIp));
            _ni = new NotifyIcon {Icon = new Icon(Properties.Resources.main, 16, 16)};
            _ni.Click += 
            delegate
            {
                Show();
                WindowState = WindowState.Normal;
                _ni.Visible = false;
            };

        }
        #endregion Public members

        #region Private members

        private static string GetLocalIp()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                var localIp = ip.ToString();
                var temp = localIp.Split('.');
                if (ip.AddressFamily == AddressFamily.InterNetwork &&
                    (temp[0] == "192" || temp[0] == "10" || temp[0] == "169" || temp[0] == "172"))
                    return ip.ToString();
            }
            return null;
        }

        private void ResolveExternalIp()
        {
            LblShowExtIp.Content = "...discover";
            _svr.ResolveExtIp(OnExtIp);
        }

        private void OnPing(object sender, PingCompletedEventArgs eventArgs)
        {
            LblInetStatus.Content = _svr.IsInet ? "Internet connection is alive!" : "Internet connection failed...";
        }

        private void OnExtIp(object sender, EventArgs eventArgs)
        {
            LblShowExtIp.Content = _svr.ExtAddress;
        }

        private void btnExit_Click(object sender, RoutedEventArgs e)
        {
            if (_svr.IsWorking)
                btnStartStop_Click(sender, e);//stops server
            _canClose = true;
            Close();
        }

        private void btnToTray_Click(object sender, RoutedEventArgs e)
        {
            _ni.Visible = true;
            WindowState = WindowState.Minimized;
        }

        private void Window_StateChanged(object sender, EventArgs e)
        {
            if (WindowState == WindowState.Minimized)
                Hide();
        }

        private void ShowConnectState()
        {
            var bi = new BitmapImage();
            if (_svr.IsWorking)
            {
                BtnStartStop.Content = "Stop";
                bi.BeginInit();
                bi.UriSource = new Uri("Resources/on16.png", UriKind.Relative);
            }
            else//stopped
            {
                BtnStartStop.Content = "Start";
                bi.BeginInit();
                bi.UriSource = new Uri("Resources/off16.png", UriKind.Relative);
            }
            bi.EndInit();
            ImgState.Source = bi;
        }

        private void btnStartStop_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_svr.IsWorking)
                    _svr.Stop("Click");
                else
                {
                    var listenAddr = LblShowIntIp.Content.ToString();
                    if (RbtnExtIp.IsChecked.Equals(true))
                        listenAddr = _svr.ExtAddress;
                    if (RbtnLbkIp.IsChecked.Equals(true))
                        listenAddr = LblShowLoopBackIp.Content.ToString();
                    var result =
                        !(listenAddr == "discover..." || listenAddr == "Unknown..." || !listenAddr.Contains("."));
                    if (RbtnExtIp.IsChecked.Equals(true) && !_svr.IsInet)
                        result = false;
                    if (!result)
                        throw new ArgumentOutOfRangeException("Invalid address or no active Internet connections found");
                    _svr.Start(listenAddr, Convert.ToInt32(TxtBoxPortNum.Text));
                }
                ShowConnectState();
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message, "Server message", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                MessageBox.Show(ex.Message, "Server message", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch (SocketException ex)
            {
                MessageBox.Show("Can't start the server. the reason is: " + ex.Message,
                    "Server message", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            TxtBoxPortNum.Text = Settings.Default.ListeningPort.ToString(CultureInfo.InvariantCulture);
            _svr.Port = Convert.ToInt32(TxtBoxPortNum.Text);
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (!_canClose)
            {
                e.Cancel = true;
                btnToTray_Click(this, new RoutedEventArgs());//in fact we'd like to tray it
                return;
            }
            Settings.Default.Save();
        }

        private void BtnUpdate_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(ResolveExternalIp));
        }
        #endregion Private members
    }
}